package com.diandian.backend.dingding.exchange.service;

import com.alibaba.fastjson2.JSON;
import com.diandian.dingding.boot.starter.dto.DingDingApplicationTokenDTO;
import com.diandian.dingding.boot.starter.service.DingdingApplicationTokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class DingdingTokenService {

    private static final Logger logger = LoggerFactory.getLogger(DingdingTokenService.class);

    @Autowired
    private DingdingApplicationTokenService dingdingApplicationTokenService;

    @Autowired
    private RedisTemplate redisTemplate;

    private final static String DINGDING_APPLICATION_TOKEN_CACHE_PREFIX = "dingtalk:token:";

    /**
     * 在使用access_token时，请注意：
     * access_token的有效期为7200秒（2小时），有效期内重复获取会返回相同结果并自动续期，过期后获取会返回新的access_token。
     * 开发者需要缓存access_token，用于后续接口的调用。因为每个应用的access_token是彼此独立的，所以进行缓存时需要区分应用来进行存储。
     * 不能频繁调用gettoken接口，否则会受到频率拦截。
     */
    public String getToken(String appKey, String appSecret) throws Exception{

        // 从缓存获取数据
        String cacheKey = DINGDING_APPLICATION_TOKEN_CACHE_PREFIX + appKey;
        String cacheToken = getTokenFromCache(cacheKey);

        // 缓存中没有，则执行更新token
        if(cacheToken == null || "".equals(cacheToken)){
            logger.info("未从缓存中获取到抖音本地生活token数据...");
            return updateToken(appKey, appSecret, cacheKey);
        }

        // 数据结构转换
        DingDingApplicationTokenDTO cacheData = JSON.parseObject(cacheToken, DingDingApplicationTokenDTO.class);

        // 缓存中token的已过有效期
        Date expiresDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(cacheData.getOverdueTime());
        boolean isExpiresFlag = expiresDate.before(new Date());
        if(isExpiresFlag){
            logger.info("从缓存中获取的钉钉token已过期，将重新进行token获取...");
            return updateToken(appKey, appSecret, cacheKey);
        }

        logger.info("从缓存中获取钉钉token成功，token信息：" + JSON.toJSONString(cacheData));

        return cacheData.getAccessToken();
    }

    /**
     * 从缓存中获取应用token
     * 说明：存在且有效，则使用；否则重新获取后更新。每个应用的token时独立的，需要隔离管理
     */
    private String getTokenFromCache(String cacheKey){
        Object resultObj = redisTemplate.opsForValue().get(cacheKey);
        return resultObj == null ? null : String.valueOf(resultObj);
    }

    /**
     * 调用钉钉获取新的token，刷新缓存中的token
     * @param appKey
     * @param appSecret
     * @param cacheKey
     */
    private String updateToken( String appKey, String appSecret, String cacheKey){

        // 从抖音获取token
        DingDingApplicationTokenDTO tokenResponse = dingdingApplicationTokenService.tokenRequest(appKey, appSecret);
        if(tokenResponse == null || tokenResponse.getAccessToken() == null || "".equals(tokenResponse)){
            logger.info("未从钉钉服务获取到应用{}的token数据...", appKey);
            return null;
        }

        // 设置缓存
        redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(tokenResponse));

        // 返回token
        return tokenResponse.getAccessToken();
    }
}
